#ifndef __SOCKET_HPP__
#define __SOCKET_HPP__
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include "Util.hpp"
#include <stdlib.h>
#include <cstring>
#include <functional>
#include "Inetaddr.hpp"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string>
namespace socket_ns
{
    class Base_Socket;
    using socket_ptr = std::shared_ptr<Base_Socket>;
    using recv_function = std::function<int(std::string& out)>;
    const int gbacklog = 8;
    class Base_Socket
    {
        public:
            //套接字子接口
            virtual void CreateSocketOrDie() = 0; //创建套接字
            virtual void BindSocketOrDie(InetAddr& addr) = 0; //绑定套接字
            virtual void ListenSocketOrDie() = 0; //设置监听套接字
            virtual socket_ptr Accepter(InetAddr* addr,int*errcode) = 0; //接收客户端
            virtual bool Connector(InetAddr& addr) = 0; //客户端接口，向addr发送连接请求
            virtual void SetSocketAddrReuse() = 0; //设置服务器地址服用
            virtual int Sockfd() = 0; //返回套接字id
            virtual int Recv(recv_function rf,std::string& out) = 0; //接收来自客户端的消息，并把消息放在out中
            virtual int Send(const std::string &in) = 0; //客户端发送消息给服务器的接口
            virtual void Close() = 0; //关闭套接字
        public:
            //供外部调用的接口
            void BuildListenSocket(InetAddr &addr) //自动建立listen套接字
            {
                //1.创建套接字
                CreateSocketOrDie();
                //2.设置套接字地址复用
                SetSocketAddrReuse();
                //3.绑定套接字
                BindSocketOrDie(addr);
                //4.设置listen套接字监听状态
                ListenSocketOrDie();
            }
            bool BuildClientSocket(InetAddr& addr) //自动建立客户端的套接字
            {
                //1.创建套接字
                CreateSocketOrDie();
                //2.直接发起连接
                return Connector(addr);
            }
    };

    class TcpSocket : public Base_Socket
    {
        public:
            //成员函数
            TcpSocket(int sockfd = -1) : _sockfd(sockfd){}
            // ~TcpSocket(){
            //     if(_sockfd > 0)
            //         Close();
            // }
        public:
            void CreateSocketOrDie() override
            {
                _sockfd = socket(AF_INET,SOCK_STREAM,0);
                if(_sockfd < 0)
                {
                    ELOG("socket create error , process exit");
                    exit(SOCKET_ERROR);
                }
                SetNonBlock(_sockfd);
                ILOG("socket create success!");
            }
            virtual void BindSocketOrDie(InetAddr& addr) override
            {
                struct sockaddr_in local = addr.Addr();
                socklen_t len = sizeof(local);
                int n = bind(_sockfd,reinterpret_cast<sockaddr*>(&local),len);
                if(n < 0)
                {
                    ELOG("server sockfd:%d,Bind Error , process exit!");
                    Close();
                    exit(BIND_ERROR);
                }
                ILOG("server socket bind success!");
            }
            virtual void ListenSocketOrDie() override
            {
                int n = listen(_sockfd,gbacklog);
                if(n < 0)
                {
                    ELOG("server sockfd:%d listen error!,process exit!");
                    Close();
                    exit(LISTEN_ERROR);
                }
                ILOG("server sockfd listen success!");
            }
            virtual socket_ptr Accepter(InetAddr* addr,int* errcode) override
            {
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                std::cout << _sockfd << std::endl;
                int sockfd = accept(_sockfd,reinterpret_cast<sockaddr*>(&peer),&len);
		ILOG("客户端连接 %d",sockfd);
                *errcode = errno;
                if(sockfd < 0)
                {
                    ELOG("listen sock accept error");
                }
                //addr保存客户端信息
                *addr = peer;
                if(sockfd > 0) SetNonBlock(sockfd);
                socket_ptr sock = std::make_shared<TcpSocket>(sockfd);
                return sock;
            }
            virtual bool Connector(InetAddr& addr) override
            {
                struct sockaddr_in svraddr;
                memset(&svraddr,0,sizeof(svraddr));
                svraddr = addr.Addr();
                socklen_t len = sizeof(svraddr);
                int n = connect(_sockfd,reinterpret_cast<sockaddr*>(&svraddr),len);
                if(n < 0)
                {
                    DLOG("sockfd:%d Connect error!",_sockfd);
                    return false;
                }
                ILOG("sockfd:%d connect success!",_sockfd);
                return true;
            }
            virtual void SetSocketAddrReuse() override
            {
                int optval = 1;
                int n = setsockopt(_sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval));
                if(n < 0)
                {
                    ELOG("set server reuse error!");
                }
                ILOG("set server reuse success!");
            }
            virtual int Sockfd() override
            {
                return _sockfd;
            }
            virtual int Recv(recv_function rf,std::string& out) override
            {
                int num = rf(out);
                return num;
            }
            virtual int Send(const std::string &in) override
            {
                ssize_t n = send(_sockfd,in.c_str(),in.size(),0);
                if(n < 0)
                {
                    ELOG("Send Error!sockfd:%d",_sockfd);
                }else if(n < in.size()){
                    
                }
            }
            virtual void Close() override
            {
                int n = close(_sockfd);
                if(n < 0)
                {
                    ELOG("Close sockfd:%d error" , _sockfd);
                }
                ILOG("Close sockfd success! %d",_sockfd);
            }

            private:
                int _sockfd;
    };
};
#endif
